use crate::config::app_error::AppResult;
use crate::extension::index::index::indexer::DefaultIndexer;
use crate::extension::index::index::query::query::query_factory::Query;
use crate::extension::index::index::query::query::{BaseQuery, QueryIndexView};
use anyhow::anyhow;
use halo_model::{ExtensionOperator, GVK};
use ordermap::OrderSet;
use std::hash::Hash;

pub struct And {
    pub child_queries: Vec<Query>,
    pub size: usize,
}

impl And {
    pub fn new(child_queries: Vec<Query>) -> AppResult<Self> {
        let len = child_queries.len();
        if len < 2 {
            return Err(anyhow!(
                "An 'And' query cannot have fewer than 2 child queries, {} were supplied",
                len
            )
            .into());
        }
        Ok(And {
            child_queries,
            size: len,
        })
    }
}

impl BaseQuery for And {
    fn matches(
        &self,
        index_view: &QueryIndexView<DefaultIndexer>,
    ) -> AppResult<OrderSet<String>> {
        let mut result = OrderSet::new();
        for query in &self.child_queries {
            let set = query.matches(index_view)?;
            if result.is_empty() {
                result.extend(set);
            } else {
                result.retain(|item| set.iter().all(|set| set.contains(item)));
            }
        }
        Ok(result)
    }
}
